package ar.edu.itba.it.cg.grupo01.impl.scene.optimization;

import static com.google.common.base.Preconditions.checkNotNull;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import ar.edu.itba.it.cg.grupo01.api.Intersection;
import ar.edu.itba.it.cg.grupo01.api.Ray;
import ar.edu.itba.it.cg.grupo01.api.shape.Shape;
import ar.edu.itba.it.cg.grupo01.impl.IntersectionFactory;
import ar.edu.itba.it.cg.grupo01.impl.shape.AABB;

class Internal extends OctNode {
	private List<OctNode> childs;

	Internal(Collection<? extends Shape> shapes, AABB box, int shapesPerNode,
			int maxDepth, IntersectionFactory intersectionFactory) {
		super(box, intersectionFactory);
		checkNotNull(shapes, "Shapes should not be null");

		ArrayList<Shape> inBox = new ArrayList<Shape>();
		for (Shape shape : shapes) {
			if( shape.containedInAABB(box) ) {
				inBox.add(shape);
			}
		}
		//Done with shapes
		shapes = null;
		
		//Used ArrayList to use this operation
		inBox.trimToSize();
		
		childs = new ArrayList<OctNode>(8);
		for (AABB miniBox : box.split()) {
			childs.add(OctNode.of(inBox, miniBox, shapesPerNode, maxDepth - 1,
					intersectionFactory));
		}
	}

	@Override
	public Intersection<? extends Shape> intersects(Ray ray) {
		Intersection<? extends Shape> intersection = box.intersects(ray);

		if (!intersection.intersects()) {
			return intersection;
		}

		Set<Intersection<? extends Shape>> intersections = new HashSet<Intersection<? extends Shape>>();
		for (OctNode child : childs) {
			intersections.add(child.intersects(ray));
		}

		return intersectionFactory.createIntersection(intersections);
	}

	@Override
	public int getDepth() {

		List<Integer> depths = new ArrayList<Integer>();

		for (OctNode node : childs) {
			depths.add(node.getDepth());
		}

		return 1 + Collections.max(depths);
	}

	@Override
	int leafAmount() {
		
		int amount = 0;
		for (OctNode node: childs) {
			amount += node.leafAmount();
		}
		
		return amount;
	}

	@Override
	public Intersection<? extends Shape> hitsLight(Ray lightRay, Shape shape) {
		Intersection<? extends Shape> intersection = box.intersects(lightRay);

		if (!intersection.intersects()) {
			return intersection;
		}

		Set<Intersection<? extends Shape>> intersections = new HashSet<Intersection<? extends Shape>>();
		for (OctNode child : childs) {
			intersections.add(child.hitsLight(lightRay, shape));
		}

		return intersectionFactory.createIntersection(intersections);
	
	}

}
